package com.biz.primus.ms.promotion.dao.po;

import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.common.utils.JsonUtils;
import com.biz.primus.model.promotion.enums.PromotionTargetLimitTypeEnum;
import com.biz.primus.base.enums.PromotionTypeEnum;
import com.biz.primus.model.promotion.exception.PromotionExceptionType;
import com.biz.primus.model.promotion.vo.OrderPromotionDetailVo;
import com.biz.primus.model.promotion.vo.RaisePriceRedemptionRuleVo;
import com.biz.primus.model.promotion.vo.RedemptionProductVo;
import com.biz.primus.model.promotion.vo.req.OrderPromotionReqDetailVo;
import com.biz.primus.ms.base.jpa.converter.ListStringConverter;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * 加价换购促销
 *
 * @author david-liu
 */
@Entity
@Getter
@Setter
public class RaisePriceRedemptionPromotion extends BasePromotion {
    private static final long serialVersionUID = 9161063384073757339L;

    // 促销门槛限制方式(按照金额还是按照数量)
    @Enumerated(value = EnumType.STRING)
    private PromotionTargetLimitTypeEnum limitType;

    /**
     * 限制金额(单位: 分)
     */
    private Integer limitAmount;

    /**
     * 限制数量
     */
    private Integer limitQuantity;

    // 换购的目标商品ID
    @Column(columnDefinition = "TEXT")
    @Convert(converter = ListStringConverter.class)
    private List<Long> redemptionProductIds;

    /**
     * 是否启用阶梯加价换购
     */
    private Boolean isStairCut = false;

    /**
     * 促销规则, 存放RaisePriceRedemptionRuleVo JSON
     *
     * @see RaisePriceRedemptionRuleVo
     */
    @Column(columnDefinition = "TEXT")
    private String raisePriceRedemptionRule;

    @Transient
    private RaisePriceRedemptionRuleVo raisePriceRedemptionRuleVo;

    @Override
    public boolean isMatchPromotionRule(OrderPromotionReqDetailVo detailVo) {
        AssertUtils.isTrue(Objects.nonNull(detailVo), PromotionExceptionType.ILLEGAL_PARAMETER);
        detailVo.postProcess();
        List<Long> promotionEffectProductIds = this.getPromotionEffectProductIds(detailVo);
        if (CollectionUtils.isEmpty(promotionEffectProductIds)) {
            return false;
        }
        RaisePriceRedemptionRuleVo raisePriceRedemptionRuleVo = this.getRaisePriceRedemptionRule();
        Map.Entry<Integer, Integer> entry = raisePriceRedemptionRuleVo.getRaiseRedemptionRule().entrySet().iterator().next();
        if (raisePriceRedemptionRuleVo.getLimitType() == PromotionTargetLimitTypeEnum.DISCOUNT_BY_PRODUCT_AMOUNT) {
            return entry.getKey() <= promotionEffectProductIds.stream().map(detailVo::getProductAmount).reduce(0, (acc, item) -> acc = acc + item);
        } else {
            return entry.getKey() <= promotionEffectProductIds.stream().map(detailVo::getRequestProductQuantity).reduce(0, (acc, item) -> acc = acc + item);
        }
    }

    @Override
    public OrderPromotionDetailVo getOrderPromotionDetail(OrderPromotionReqDetailVo reqDetailVo) {
        AssertUtils.isTrue(Objects.nonNull(reqDetailVo), PromotionExceptionType.ILLEGAL_PARAMETER);
        reqDetailVo.postProcess();
        List<Long> promotionEffectProductIds = this.getPromotionEffectProductIds(reqDetailVo);
        OrderPromotionDetailVo detailVo = new OrderPromotionDetailVo();
        detailVo.setId(this.getId());
        detailVo.setName(this.getName());
        detailVo.setDescription(this.getDescription());
        detailVo.setAllowCoupon(this.getAllowCoupon());
        detailVo.setPromotionType(PromotionTypeEnum.RAISE_PRICE_REDEMPTION);
        detailVo.setEffectProductIds(promotionEffectProductIds);
        RaisePriceRedemptionRuleVo raisePriceRedemptionRule = this.getRaisePriceRedemptionRule();
        Integer promotionCalculateCondition;
        if (raisePriceRedemptionRule.getLimitType() == PromotionTargetLimitTypeEnum.DISCOUNT_BY_PRODUCT_AMOUNT) {
            promotionCalculateCondition = promotionEffectProductIds.stream().map(reqDetailVo::getProductAmount).reduce(0, (acc, item) -> acc = acc + item);
        } else {
            promotionCalculateCondition = promotionEffectProductIds.stream().map(reqDetailVo::getRequestProductQuantity).reduce(0, (acc, item) -> acc = acc + item);
        }
        Map.Entry<Integer, Integer> matchingRule = null;
        if (raisePriceRedemptionRule.getIsStairCut()) {
            for (Map.Entry<Integer, Integer> entry : raisePriceRedemptionRule.getRaiseRedemptionRule().entrySet()) {
                if (Objects.isNull(matchingRule) || matchingRule.getKey() <= promotionCalculateCondition) {
                    matchingRule = entry;
                } else {
                    break;
                }
            }
        } else {
            matchingRule = raisePriceRedemptionRule.getRaiseRedemptionRule().entrySet().iterator().next();
        }
        AssertUtils.notNull(matchingRule, PromotionExceptionType.ILLEGAL_STATE);
        AssertUtils.isTrue(CollectionUtils.isNotEmpty(this.redemptionProductIds), PromotionExceptionType.ILLEGAL_STATE);
        RedemptionProductVo redemptionProductVo = new RedemptionProductVo();
        redemptionProductVo.setRaisePrice(matchingRule.getValue());
        redemptionProductVo.setUserOnceRedemptionQuantity(raisePriceRedemptionRule.getUserOnceRedemptionQuantity());
        redemptionProductVo.setRedemptionProductIds(this.redemptionProductIds);
        detailVo.setRedemptionProductVo(redemptionProductVo);
        return detailVo;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }

    private RaisePriceRedemptionRuleVo getRaisePriceRedemptionRule() {
        AssertUtils.isTrue(StringUtils.isNoneBlank(this.raisePriceRedemptionRule), PromotionExceptionType.ILLEGAL_STATE);
        if (Objects.isNull(this.raisePriceRedemptionRuleVo)) {
            this.raisePriceRedemptionRuleVo = JsonUtils.json2Obj(this.raisePriceRedemptionRule, RaisePriceRedemptionRuleVo.class);
        }
        RaisePriceRedemptionRuleVo raisePriceRedemptionRule = this.raisePriceRedemptionRuleVo;
        boolean isValid = Objects.nonNull(raisePriceRedemptionRule) && Objects.nonNull(raisePriceRedemptionRule.getIsStairCut())
                && Objects.nonNull(raisePriceRedemptionRule.getLimitType())
                && MapUtils.isNotEmpty(raisePriceRedemptionRule.getRaiseRedemptionRule());
        AssertUtils.isTrue(isValid, PromotionExceptionType.ILLEGAL_STATE);
        return raisePriceRedemptionRule;
    }

}
